﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using PhotoGallery.Models;
using PhotoGallery.Repositories;
using QCloud.CosApi.Api;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace PhotoGallery.Utils
{
    public static class ServerHelper
    {
        private static readonly string[] _extensions = { ".jpg", ".jpeg", ".gif", ".png" };

        #region 腾讯云存储参数，请在Startup中初始化
        public static int APP_ID { get; set; }

        public static string SECRET_ID { get; set; }
        public static string SECRET_KEY { get; set; }

        public static string BucketName { get; set; }

        public static string RemotePath { get; set; }

        private static CosCloud _cosCloud = null;
        #endregion


        /// <summary>
        /// 获取当前请求中IP
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static String GetIP(HttpContext context)
        {
            return context.Connection.RemoteIpAddress.ToString();
        }

        /// <summary>
        /// 获取配置文件中的Token过期时间
        /// </summary>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static TimeSpan GetTimeSpan(IConfiguration configuration)
        {
            var strExpires = configuration["JwtBearer:Expires"];
            TimeSpan ExpiresSpan = TimeSpan.FromDays(30);
            if (!string.IsNullOrEmpty(strExpires))
            {
                //格式 时间标识符:长度 (时间标识符 y:年,M:月,d:日, H:时,m:分,s:秒) 例如d:15 表示15天,如果值为0表示不过期
                var split = strExpires.Split(':');
                if (split != null && split.Length == 2)
                {
                    var num = 0L;
                    long.TryParse(split[1], out num);
                    if (num == 0)
                    {
                        ExpiresSpan = TimeSpan.Zero;
                    }
                    else
                    {
                        switch (split[0])
                        {
                            case "y":
                                ExpiresSpan = TimeSpan.FromDays(365 * num);
                                break;
                            case "M":
                                ExpiresSpan = TimeSpan.FromDays(30 * num);
                                break;
                            case "d":
                                ExpiresSpan = TimeSpan.FromDays(num);
                                break;
                            case "H":
                                ExpiresSpan = TimeSpan.FromHours(num);
                                break;
                            case "m":
                                ExpiresSpan = TimeSpan.FromMinutes(num);
                                break;
                            case "s":
                                ExpiresSpan = TimeSpan.FromSeconds(num);
                                break;
                            default:
                                break;
                        }
                    }

                }
            }

            return ExpiresSpan;
        }

        /// <summary>
        /// 计算文件的SHA1
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static String GetFileHash(string filePath)
        {
            if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
            {
                throw new ArgumentException("filePath为空或者传入文件不存在");
            }
            var hash = "";
            using (var file = File.Open(filePath, FileMode.Open))
            {
                var sha1 = SHA1.Create();
                hash = BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", "");
            }
            return hash;

        }

        /// <summary>
        /// 判断是否为图片格式
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public static bool IsImageFile(string file)
        {
            string ext = Path.GetExtension(file);
            return _extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// 搜索网站根目录下albums文件夹下图片信息，上传到腾讯云存储并写入本地数据库
        /// </summary>
        /// <param name="repo"></param>
        /// <param name="contentPath"></param>
        public static void InitializeAlbumsCollection(PhotoGalleryRepository repo, string contentPath)
        {
            var albums = SearchLoaclAlbums(contentPath);
            if (albums == null || albums.Count < 1)
            {
                Console.WriteLine("本地目录为空");
            }
            else
            {
                //清空Album和Photo数据库     
                var ret = repo.Database.ExecuteSqlCommand("delete from Photos");
                Console.WriteLine("清空Photos");
                ret = repo.Database.ExecuteSqlCommand("delete from Albums");
                Console.WriteLine("清空Albums");
                var photos = new List<PhotoInfoModel>();
                for (var i = 0; i < albums.Count; i++)
                {
                    var album = albums[i];
                    for (var j = 0; j < album.Photos.Count; j++)
                    {
                        var photo = album.Photos[j];
                        var newPhoto = UploadLocalPhoto(photo);
                        if(photos.FirstOrDefault(w=>!string.IsNullOrEmpty(newPhoto.Hash) && w.Hash == newPhoto.Hash) == null)
                        {
                            photos.Add(newPhoto);
                        }
                    }
                    var cover = photos.FirstOrDefault()?.CDNUrl;
                    if (!string.IsNullOrEmpty(cover))
                    {
                        album.CoverPhoto = cover;
                    }
                    else
                    {
                        album.CoverPhoto = CacheKeys.AlbumsEmptyUrl;
                    }

                    repo.Albums.Add(album);
                }
                repo.Photos.AddRange(photos);
                //保存到数据库
                var ret1 = repo.SaveChanges();
            }

        }

        private static PhotoInfoModel UploadLocalPhoto(PhotoInfoModel photo)
        {
            var filePath = photo.LocalPath;
            //复制对象
            var jsonObj = JsonConvert.SerializeObject(photo);
            var retModel = JsonConvert.DeserializeObject<PhotoInfoModel>(jsonObj);

            if (File.Exists(filePath))
            {
                var imgPath = "";
                var hash = "";// MakeSHA1(filePath);
                using (var fileStream = File.OpenRead(filePath))
                {
                    hash = MakeSHA1(filePath);
                    fileStream.Seek(0, SeekOrigin.Begin);
                    var imgProc = new ImageProcessor();
                    imgPath = imgProc.CreateThumbnails(fileStream, filePath, hash);
                }
                var jsonRet = Utils.ServerHelper.UploadFile(filePath);
                var obj = JsonConvert.DeserializeObject<FileUploadResult>(jsonRet);
                if (obj != null && obj.code == 0)
                {
                    Console.WriteLine("上传图片成功:" + photo.LocalPath);
                    //上传成功
                    retModel.Hash = hash;
                    retModel.UploadClient = 2;
                    retModel.UploadDate = DateTime.Now;
                    retModel.UploadUser = "server";
                    retModel.CDNUrl = obj.data.access_url;
                    retModel.CDNUrl2 = obj.data.source_url;
                }

            }
            return retModel;
        }

        /// <summary>
        /// 搜索本地相册文件夹
        /// </summary>
        /// <param name="contentPath"></param>
        /// <returns></returns>
        public static List<AlbumInfoModel> SearchLoaclAlbums(string contentPath)
        {
            List<AlbumInfoModel> albumList = new List<AlbumInfoModel>();
            var root = Path.Combine(contentPath, "albums");
            if (!Directory.Exists(root))
                return null;
            var publicAlbumsPath = Path.Combine(root, "public");
            if (!Directory.Exists(publicAlbumsPath))
            {
                Directory.CreateDirectory(publicAlbumsPath);
            }
            var userAlbumsPath = Path.Combine(root, "user");
            if (!Directory.Exists(userAlbumsPath))
            {
                Directory.CreateDirectory(userAlbumsPath);
            }
            //公开相册 目录地址类似 /albums/public/相册文件夹....
            var albumPaths = Directory.EnumerateDirectories(publicAlbumsPath);
            foreach (string albumPath in albumPaths)
            {
                var dir = new DirectoryInfo(albumPath);
                var album = GetAlbum(dir);
                albumList.Add(album);
            }
            //用户相册 目录地址类型 /albums/user/{用户名}/相册文件夹
            var usersPaths = Directory.EnumerateDirectories(userAlbumsPath);
            foreach (var usrPath in usersPaths)
            {
                var usersDir = Directory.EnumerateDirectories(usrPath);
                foreach (string albumPath in usersDir)
                {
                    var dir = new DirectoryInfo(albumPath);
                    if ("thumbnail".Equals(dir.Name, StringComparison.OrdinalIgnoreCase)) continue;
                    var album = GetAlbum(dir, 1);
                    albumList.Add(album);
                }
            }
            return albumList;
        }

        /// <summary>
        /// 获取相册实体对象
        /// </summary>
        /// <param name="albumDir">相册路径</param>
        /// <param name="albumType">相册类型 0：公开相册，1：用户相册;默认公开相册</param>
        /// <returns></returns>
        private static AlbumInfoModel GetAlbum(DirectoryInfo albumDir, int albumType = 0)
        {
            var directory = albumDir;


            var album = new AlbumInfoModel();

            album.Id = Guid.NewGuid().ToString();
            album.Name = directory.Name;
            album.AlbumType = albumType;
            album.CreateDate = directory.CreationTime;
            album.Description = directory.Name;
            var photoPath = "";
            if (albumType == 0)
            {
                //公共目录: /albums/public/相册名字
                album.AlbumPath = photoPath = $"albums/public/{album.Name.Replace(" ", "%20")}/";

            }
            else
            {
                //用户目录: /albums/user/用户名/相册名字
                album.AlbumPath = photoPath = $"albums/user/{directory.Parent.Name.Replace(" ", "%20")}/{album.Name.Replace(" ", "%20")}/";
                album.Owner = albumDir.Parent.Name;
            }

            var photos = directory.EnumerateFiles()
                .Where(f => Utils.ServerHelper.IsImageFile(f.FullName))
                .Select(a => new PhotoInfoModel() { AlbumName = album.Name, Name = a.Name, Path = photoPath + a.Name, LocalPath = a.FullName }).ToList();
            var cover = photos.FirstOrDefault();

            album.CoverPhoto = GetCoverUrl(cover);
            album.Photos = photos;
            return album;
        }

        /// <summary>
        /// 获取封面图片地址
        /// </summary>
        /// <param name="photo"></param>
        /// <returns></returns>
        private static string GetCoverUrl(PhotoInfoModel photo)
        {
            if (photo == null) return CacheKeys.AlbumsEmptyUrl; //相册为空占位符
            var coverUrl = photo?.Path ?? CacheKeys.AlbumsEmptyUrl;
            if (string.IsNullOrEmpty(photo.CDNUrl))
            {
                if (!string.IsNullOrEmpty(photo.CDNUrl2))
                {
                    coverUrl = photo.CDNUrl2;
                }
            }
            else
            {
                coverUrl = photo.CDNUrl;
            }

            return coverUrl;
        }

        public static string MakeSHA1(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new ArgumentNullException("文件不存在，请传入有效文件路径");
            }
            var fileStream = File.OpenRead(filePath);
            return MakeSHA1(fileStream);
        }

        public static string MakeSHA1(Stream steam)
        {
            var sha1 = SHA1.Create();
            var hash = BitConverter.ToString(sha1.ComputeHash(steam)).Replace("-", "");
            return hash;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="appId">腾讯云存储APP_ID</param>
        /// <param name="secretId">腾讯云存储</param>
        /// <param name="secretKey">腾讯云存储</param>
        /// <param name="bucketName">腾讯云存储BucketName</param>
        /// <param name="remotePathFileName">需要上传到腾讯云存储的文件名，带路径</param>
        /// <param name="filePath">需要上传的文件路径</param>
        /// <returns></returns>
        private static async Task<string> UploadFile(int appId, string secretId, string secretKey, string bucketName, string remotePathFileName, string filePath)
        {
            var cos = new CosCloud(appId, secretId, secretKey);
            return await UploadFile(cos, bucketName, remotePathFileName, filePath);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="cosObj">CosCloud对象</param>
        /// <param name="bucketName">腾讯云存储BucketName</param>
        /// <param name="remotePathFileName">需要上传到腾讯云存储的文件名，带路径</param>
        /// <param name="filePath">需要上传的文件路径</param>
        /// <returns></returns>
        public static async Task<string> UploadFile(CosCloud cosObj, string bucketName, string remotePathFileName, string filePath)
        {
            if (cosObj == null) throw new ArgumentNullException("cosObj参数不能为空");
            return await Task.Run(() =>
             {
                 return cosObj.UploadFile(bucketName, remotePathFileName, filePath);
             });
        }

        /// <summary>
        /// 上传文件 -异步
        /// 需要先初始化腾讯云存储的参数
        /// </summary>
        /// <param name="filePath">需要上传的文件路径</param>
        /// <returns></returns>
        public static async Task<string> UploadFileAsync(string filePath)
        {
            if (string.IsNullOrEmpty(BucketName) || string.IsNullOrEmpty(SECRET_ID) || string.IsNullOrEmpty(SECRET_KEY) || APP_ID == default(int))
            {
                throw new ArgumentNullException("请先初始化腾讯云存储参数");
            }
            return await Task.Run(() =>
             {
                 if (_cosCloud == null)
                 {
                     _cosCloud = new CosCloud(APP_ID, SECRET_ID, SECRET_KEY);
                 }
                 var fileName = string.Format("{0}/{1}", RemotePath, Path.GetFileName(filePath));
                 return _cosCloud.UploadFile(BucketName, fileName, filePath);
             });
        }

        /// <summary>
        /// 上传文件 
        /// 需要先初始化腾讯云存储的参数
        /// </summary>
        /// <param name="filePath">需要上传的文件路径</param>
        /// <returns></returns>
        public static string UploadFile(string filePath)
        {
            if (string.IsNullOrEmpty(BucketName) || string.IsNullOrEmpty(SECRET_ID) || string.IsNullOrEmpty(SECRET_KEY) || APP_ID == default(int))
            {
                throw new ArgumentNullException("请先初始化腾讯云存储参数");
            }
            if (_cosCloud == null)
            {
                _cosCloud = new CosCloud(APP_ID, SECRET_ID, SECRET_KEY);
            }
            var fileName = string.Format("{0}/{1}", RemotePath, Path.GetFileName(filePath));
            return _cosCloud.UploadFile(BucketName, fileName, filePath);
        }

        public static List<string> SplitCsv(this string csvList, bool nullOrWhitespaceInputReturnsNull = false)
        {
            if (string.IsNullOrWhiteSpace(csvList))
                return nullOrWhitespaceInputReturnsNull ? null : new List<string>();

            return csvList
                .TrimEnd(',')
                .Split(',')
                .AsEnumerable<string>()
                .Select(s => s.Trim())
                .ToList();
        }

        public static bool IsNullOrWhitespace(this string s)
        {
            return String.IsNullOrWhiteSpace(s);
        }
    }
}
